// Tencent is pleased to support the open source community by making
// 蓝鲸智云 - 监控平台/日志平台 (BlueKing - Monitor/Log) available.
// Copyright (C) 2017-2022 THL A29 Limited, a Tencent company. All rights reserved.
// Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://opensource.org/licenses/MIT
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//

package oneapm

import (
	"errors"
	"fmt"
	"strings"

	"github.com/TencentBlueKing/bkmonitor-kits/logger"
	oneapmproto "go.opentelemetry.io/collector/pkg/translator/oneapm/proto"

	"github.com/TencentBlueKing/bk-collector/receiver"
)

func (s httpSrv) handleAgentCommand(req *oneapmproto.AgentCommandRequest) (*oneapmproto.AgentCommandResponse, error) {
	response := &oneapmproto.AgentCommandResponse{}
	var cmds []*oneapmproto.AgentCommandInfo

	if req.Resource == nil {
		return nil, errors.New("oneapm: 'request.Resource' is nil pointer")
	}

	id := receiver.Identifier{
		Token:    req.Resource.DataToken,
		Service:  req.Resource.ServiceName,
		Instance: s.wrapIdentifier(req.Resource),
	}

	hashCode, found, err := receiver.GetCacheHolder().GetHashCode(id)
	// 获取 hashcode 失败
	if err != nil {
		return response, fmt.Errorf("failed to get hashcode %v, err: %v", id, err)
	}

	// 没找到对应配置
	if !found {
		return response, fmt.Errorf("no config content found: %v", id)
	}

	// hashcode 没有发生变化
	if hashCode == req.Hashcode {
		return response, nil
	}

	// hashcode 发生变化
	logger.Debugf("/AgentCommand hashcode has changed, previous=%v, current=%v, Identifier: %+v", req.Hashcode, hashCode, id.Instance)
	cmds = append(cmds, &oneapmproto.AgentCommandInfo{
		Type: 3, // 重连
	})
	response.Commands = cmds
	return response, nil
}

func (s httpSrv) handleAgentConnect(req *oneapmproto.AgentConnectRequest) *oneapmproto.ServiceResponse {
	instanceId := s.wrapIdentifier(req.Resource)

	response := &oneapmproto.ServiceResponse{}
	response.AgentSetting = &oneapmproto.AgentSetting{}
	response.State = 1
	response.Identifier = []byte(instanceId)

	id := receiver.Identifier{
		Token:    req.Resource.DataToken,
		Service:  req.Resource.ServiceName,
		Instance: instanceId,
	}

	hashCode, found, err := receiver.GetCacheHolder().GetHashCode(id)
	// 获取 hashcode 失败
	if err != nil {
		logger.Errorf("failed to get hashcode %v, err: %v", id, err)
		return response
	}
	// 没找到对应配置
	if !found {
		logger.Errorf("no config content found: %v", id)
		return response
	}

	// 如果 hashcode 找到了那 content 就一定会有
	content, _, err := receiver.GetCacheHolder().GetContent(id)
	if err != nil {
		logger.Errorf("failed to get content %v, err: %v", id, err)
		return response
	}

	logger.Debugf("/Connect Identifier: %v, hashcode: %v, content: %v", string(response.Identifier), hashCode, string(content))
	// 将配置内容同步给 agent
	response.AgentSetting.HashCode = hashCode
	response.AgentSetting.Setting = content
	return response
}

func (s httpSrv) wrapIdentifier(resource *oneapmproto.Resource) string {
	keys := []string{
		resource.SdkLanguage, // 语言
		resource.ServiceName, // 服务模块
		resource.HostName,    // 服务部署所在 Hostname
		resource.HostIp,      // 服务部署所在 IP
		resource.HostPort,    // 服务监听端口
	}
	return strings.Join(keys, ":")
}
